#include "stdafx.h"
#include "FindHelper.h"
#include <assert.h>
#include <codecvt>

FindHelper::FindHelper()
{
}


FindHelper::~FindHelper()
{
}

bool FindHelper::SetWhatVector(const WhatCharactersVector& inVector)
{
	mWhatCharactersVector = inVector;
	mBytesAbove.clear();
	mBytesBelow.clear();

	int length1 = 0;	// length of uppercase string
	int length2 = 0;	// length of lowercase string
	for (size_t i = 0; i < mWhatCharactersVector.size(); i += 2)
	{
		int subLen1 = mWhatCharactersVector[i].size();
		int subLen2 = subLen1;
		if (i + 1 < mWhatCharactersVector.size())
		{
			if (int x = mWhatCharactersVector[i + 1].size())
			{
				subLen2 = x;
			}
		}
		length1 += subLen1;
		length2 += subLen2;
	}
	mLengthForSavedBytes = max(length1, length2);
	return (0 < mLengthForSavedBytes);
}
//
//bool FindHelper::SetSearchString(LPCTSTR inString, int inSearchKind)
//{
//	if (nullptr == inString || '\0' == inString[0])
//	{
//		return false;
//	}
//	assert(sizeof(inString[0]) == 2);
//	int len = ::wcslen(inString);
//	ByteVector& vle = mWhats[SearchKind::kUtf16LE];
//	ByteVector& vbe = mWhats[SearchKind::kUtf16BE];
//	vle.clear(); vbe.clear();
//	for (const TCHAR* p = inString; *p; ++p)
//	{
//		BYTE lowByte = LOBYTE(*p);
//		BYTE highByte = HIBYTE(*p);
//		vle.push_back(lowByte); vle.push_back(highByte);
//		vbe.push_back(highByte); vbe.push_back(lowByte);
//	}
//	std::codecvt_utf8_utf16<TCHAR> cvt;
//	int maxlen = cvt.max_length();
//
//	int characterCount = vle.size() / 2;
//	ByteVector& v = mWhats[SearchKind::kUtf8];
//	v.resize(characterCount * cvt.max_length());
//	std::mbstate_t mbState = 0;
//	const TCHAR* fromNext = nullptr;
//	char* toNext = nullptr;
//	char* toBegin = (char*)&v[0];
//	auto conversionResult = cvt.out(mbState, inString, inString + characterCount,
//		fromNext, toBegin, toBegin + v.size(), toNext);
//	if (std::codecvt_utf8_utf16<WCHAR>::ok == conversionResult)
//	{
//		// trim the unused bytes (that does not contain the converted utf-8)
//		v.resize(toNext - (char*)&v[0]);
//
//		ReadHexDigits();
//	}
//	else
//	{
//		v.clear(); // will ignore search...?
//	}
//
//	bool success = (0 < characterCount);
//	mSearchKind = inSearchKind;
//	if (success && 0 <= inSearchKind)
//	{
//		success = false;
//		for (int searchKind = SearchKind::kTotalCount; searchKind--;)
//		{
//			if (searchKind == inSearchKind)
//			{
//				success = !mWhats[searchKind].empty();
//			}
//			else
//			{
//				mWhats[searchKind].clear();
//			}
//		}
//	}
//
//	mLengthForSavedBytes = 0;
//	for (int searchKind = SearchKind::kTotalCount; searchKind--;)
//	{
//		int length = mWhats[searchKind].size();
//		if (mLengthForSavedBytes < length)
//		{
//			mLengthForSavedBytes = length;
//		}
//	}
//
//	mBytesAbove.clear();
//	mBytesBelow.clear();
//	return success;
//}

void FindHelper::SetRange(const BYTE* inStartPtr, const BYTE* inEndPtr)
{
	mRangeStart = inStartPtr;
	mRangeEnd = inEndPtr;
}

bool FindHelper::SearchDown(int& outIndexBegin, int& outIndexEnd)
{
	size_t componentsCount = mWhatCharactersVector.size();
	if (0 >= componentsCount)
	{
		return false;
	}
	int index = -int(mBytesAbove.size());
	int endIndex;
	
	if (1 == componentsCount || mWhatCharactersVector[1].empty())
	{
		int lengthOfFirstSequence = mWhatCharactersVector.front().size();
		while (FindDownFirstSequence(index))
		{
			endIndex = index + lengthOfFirstSequence;
			if (ConfirmMatch(endIndex))
			{
				outIndexBegin = index;
				outIndexEnd = endIndex;
				return true;
			}
			++index;
		}
	}
	else
	{
		while (FindDownAnyOfTwoFirstSequences(index, endIndex))
		{
			if (ConfirmMatch(endIndex))
			{
				outIndexBegin = index;
				outIndexEnd = endIndex;
				return true;
			}
			++index;
		}
	}

	// copy the end of block to the "mBytesAbove" vector
	const int indexEnd = mRangeEnd - mRangeStart;
	if (int len = min(indexEnd, mLengthForSavedBytes))
	{
		mBytesAbove.assign(mRangeEnd - len, mRangeEnd);
	}

	return false;
}

bool FindHelper::SearchUp(int& outIndexBegin, int& outIndexEnd)
{
	size_t componentsCount = mWhatCharactersVector.size();
	if (0 >= componentsCount)
	{
		return false;
	}
	const int bufferLen = mRangeEnd - mRangeStart;
	int index = bufferLen;

	if (1 == componentsCount || mWhatCharactersVector[1].empty())
	{
		int lengthOfFirstSequence = mWhatCharactersVector.front().size();
		index -= lengthOfFirstSequence;
		while (FindUpFirstSequence(index))
		{
			int endIndex = index + lengthOfFirstSequence;
			if (ConfirmMatch(index))
			{
				outIndexBegin = index;
				outIndexEnd = endIndex;
				return true;
			}
			--index;
		}
	}
	else
	{
		int endIndex;
		while (FindUpAnyOfTwoFirstSequences(index, endIndex))
		{
			if (ConfirmMatch(endIndex))
			{
				outIndexBegin = index;
				outIndexEnd = endIndex;
				return true;
			}
			--index;
		}
	}

	// copy the beginning of block to the "mBytesBelow" vector
	
	if (int len = min(bufferLen, mLengthForSavedBytes))
	{
		mBytesBelow.assign(mRangeStart, mRangeStart + len);
	}
	return false;
}

/////////////////////////////////////////////////
// ---- private ----------

bool FindHelper::FindDownFirstSequence(int& ioIndex)
{
	bool isFound = false;
	int index = ioIndex;
	const auto& word = mWhatCharactersVector.front();
	const int wordLength = word.size();
	const BYTE* w = word.data();
	const BYTE* wEnd = w + wordLength;
	const BYTE firstCharacter = *w;

	if (index < 0)
	{
		// begin with the BytesAbove (the data from the previous block)
		const BYTE* pEnd = mBytesAbove.data() + mBytesAbove.size();
		for (auto p = pEnd + index; p < pEnd; )
		{
			auto p1 = reinterpret_cast<const BYTE*>(::memchr(p, firstCharacter,
				pEnd - p));
			if (nullptr == p1)
			{
				break;
			}

			int trimmedLength = min(wordLength, pEnd - p1);
			if (0 == ::memcmp(w, p1, trimmedLength))
			{
				if (trimmedLength == wordLength)
				{
					ioIndex = -int(pEnd - p1);
					return true;
				}
				int len = wordLength - trimmedLength;
				if (len <= mRangeEnd - mRangeStart &&
					0 == ::memcmp(w + trimmedLength, mRangeStart, len))
				{
					ioIndex = -int(pEnd - p1);
					return true;
				}
			}

			p = p1 + 1;
		}
		index = 0;
	}
	const BYTE* pEnd = mRangeEnd + 1 - wordLength;
	for (const BYTE* p = mRangeStart + index; p < pEnd;)
	{
		auto p1 = reinterpret_cast<const BYTE*>(
			::memchr(p, firstCharacter, pEnd - p));
		if (nullptr == p1)
		{
			break;
		}
		if (0 == ::memcmp(p1, w, wordLength))
		{
			ioIndex = p1 - mRangeStart;
			return true;
		}
		p = p1 + 1;
	}
	
	return false;
}
bool FindHelper::FindDownAnyOfTwoFirstSequences(int& ioBeginIndex, int& outEndIndex)
{
	bool isFound = false;
	int index = ioBeginIndex;
	const auto& word1 = mWhatCharactersVector[0];
	const auto& word2 = mWhatCharactersVector[1];
	const int wordLength1 = word1.size();
	const BYTE* w1 = word1.data();
	const BYTE* wEnd1 = w1 + wordLength1;
	const BYTE firstCharacter1 = *w1;
	const int wordLength2 = word2.size();
	const BYTE* w2 = word2.data();
	const BYTE* wEnd2 = w2 + wordLength2;
	const BYTE firstCharacter2 = *w2;
	if (index < 0)
	{
		// begin with the BytesAbove (the data from the previous block)
		const BYTE* pEnd = mBytesAbove.data() + mBytesAbove.size();
		if (firstCharacter1 == firstCharacter2)
		{
			for (auto p = pEnd + index; p < pEnd; ++p)
			{
				if (*p != firstCharacter1)
				{
					continue;
				}
				int len = min(wordLength1, pEnd - p);
				if (0 < len && 0 == ::memcmp(p, w1, len))
				{
					if (len == wordLength1)
					{
						ioBeginIndex = p - pEnd;
						outEndIndex = ioBeginIndex + wordLength1;
						return true;
					}
					int len2 = wordLength1 - len;
					if (len2 <= (mRangeEnd - mRangeStart) &&
						0 == ::memcmp(mRangeStart, w1 + len, len2))
					{
						ioBeginIndex = p - pEnd;
						outEndIndex = ioBeginIndex + wordLength1;
						return true;
					}
				}
				else
				{
					len = min(wordLength2, pEnd - p);
					if (0 < len && 0 == ::memcmp(p, w2, len))
					{
						if (len == wordLength2)
						{
							ioBeginIndex = p - pEnd;
							outEndIndex = ioBeginIndex + wordLength2;
							return true;
						}
						int len2 = wordLength2 - len;
						if (len2 <= (mRangeEnd - mRangeStart) &&
							0 == ::memcmp(mRangeStart, w2 + len, len2))
						{
							ioBeginIndex = p - pEnd;
							outEndIndex = ioBeginIndex + wordLength2;
							return true;
						}
					}
				}
			}
		}
		else
		{
			for (auto p = pEnd + index; p < pEnd; ++p)
			{
				if (*p == firstCharacter1)
				{
					int len = min(wordLength1, pEnd - p) - 1;
					if (0 == len || 0 == ::memcmp(p + 1, w1 + 1, len))
					{
						int len2 = wordLength1 - len - 1;
						if (0 < len2)
						{
							int bufLen = mRangeEnd - mRangeStart;
							if (len2 <= bufLen && 0 == ::memcmp(mRangeStart, w1 + 1 + len, len2))
							{
								len2 = 0;
							}
						}
						if (0 == len2)
						{
							ioBeginIndex = p - pEnd;
							outEndIndex = ioBeginIndex + wordLength1;
							return true;
						}
					}
					continue;
				}
				else if (*p == firstCharacter2)
				{
					int len = min(wordLength2, pEnd - p) - 1;
					if (0 == len || 0 == ::memcmp(p + 1, w2 + 1, len))
					{
						int len2 = wordLength2 - len - 1;
						if (0 < len2)
						{
							int bufLen = mRangeEnd - mRangeStart;
							if (len2 <= bufLen && 0 == ::memcmp(mRangeStart, w2 + 1 + len, len2))
							{
								len2 = 0;
							}
						}
						if (0 == len2)
						{
							ioBeginIndex = p - pEnd;
							outEndIndex = ioBeginIndex + wordLength2;
							return true;
						}
					}
					continue;
				}
			}
		}

		// continue with the start of the buffer
		index = 0;
	}

	// main buffer
	auto pEnd = mRangeEnd + 1 - min(wordLength1, wordLength2);
	if (firstCharacter1 == firstCharacter2)
	{
		for (auto p = mRangeStart + index; p < pEnd; ++p)
		{
			if (firstCharacter1 != *p)
			{
				continue;
			}
			if (wordLength1 <= (mRangeEnd - p) &&
				0 == memcmp(p, w1, wordLength1))
			{
				ioBeginIndex = p - mRangeStart;
				outEndIndex = ioBeginIndex + wordLength1;
				return true;
			}
			if (wordLength2 <= (mRangeEnd - p) &&
				0 == ::memcmp(p, w2, wordLength2))
			{
				ioBeginIndex = p - mRangeStart;
				outEndIndex = ioBeginIndex + wordLength2;
				return true;
			}
		}
	}
	else
	{
		for (auto p = mRangeStart + index; p < pEnd; ++p)
		{
			if (*p == firstCharacter1)
			{
				if (wordLength1 <= (mRangeEnd - p) &&
					0 == memcmp(p, w1, wordLength1))
				{
					ioBeginIndex = p - mRangeStart;
					outEndIndex = ioBeginIndex + wordLength1;
					return true;
				}
			}
			if (*p == firstCharacter2)
			{
				if (wordLength2 <= (mRangeEnd - p) &&
					0 == memcmp(p, w2, wordLength2))
				{
					ioBeginIndex = p - mRangeStart;
					outEndIndex = ioBeginIndex + wordLength2;
					return true;
				}
			}
		}
	}

	return false;
}
bool FindHelper::ConfirmMatch(int& ioIndex) const
{
	int index = ioIndex;

	int n = mWhatCharactersVector.size();
	for (int i = 2; i < n; i += 2)
	{
		auto& word = mWhatCharactersVector[i];
		if (MatchWordAtIndex(word, index))
		{
			index += word.size();
		}
		else
		{
			if (i + 1 < n)
			{
				auto& word1 = mWhatCharactersVector[i + 1];
				if (MatchWordAtIndex(word1, index))
				{
					index += word1.size();
					continue;
				}
			}
			return false;
		}
	}
	ioIndex = index;
	return true;
}

bool FindHelper::MatchWordAtIndex(const ByteVector& inWord, int inIndex) const
{
	if (inWord.empty())
	{
		return false;
	}
	const BYTE* w = inWord.data();
	const int wordLength = inWord.size();
	if (inIndex < 0)
	{
		int subLen = min(wordLength, -inIndex);
		if (0 != ::memcmp(w, &mBytesAbove[mBytesAbove.size() + inIndex], subLen))
		{
			return false;
		}
		if (int subLen1 = wordLength - subLen)
		{
			if (subLen1 + mRangeStart > mRangeEnd)
			{
				return false;
			}
			if (0 != ::memcmp(w + subLen, mRangeStart, subLen1))
			{
				return false;
			}
		}
		return true;
	}
	else
	{
		//int placeInBuffer = mRangeEnd - mRangeStart - inIndex;
		const int bufLen = mRangeEnd - mRangeStart;
		if (inIndex + wordLength <= bufLen)
		{
			return (0 == ::memcmp(w, mRangeStart + inIndex, wordLength));
		}
		else
		{
			if (inIndex < bufLen)
			{
				int subLen1 = bufLen - inIndex;
				if (0 != ::memcmp(w, mRangeStart + inIndex, subLen1))
				{
					return false;
				}
				int subLen2 = wordLength - subLen1;
				if (subLen2 >(int)mBytesBelow.size() ||
					0 != memcmp(w + subLen1, mBytesBelow.data(), subLen2))
				{
					return false;
				}
			}
			else if (inIndex - bufLen + wordLength > int(mBytesBelow.size()) ||
				0 != ::memcmp(w, &mBytesBelow[inIndex - bufLen], wordLength))
			{
				return false;
			}
		}
	}

	return true;
}

bool FindHelper::FindUpFirstSequence(int& ioIndex)
{
	const int bufLen = mRangeEnd - mRangeStart;
	int index = ioIndex;

	assert(!mWhatCharactersVector.empty());
	auto word = mWhatCharactersVector.front();
	assert(!word.empty());

	const BYTE* w = word.data();
	const int wordLength = word.size();
	const BYTE* wEnd = w + wordLength;
	const BYTE firstCharacter = *w;
	if (index >= bufLen)
	{
		const BYTE* pBelow = mBytesBelow.data();
		for (auto p = pBelow + index; p >= pBelow; --p)
		{
			if (firstCharacter != *p)
			{
				continue;
			}
			if (0 == ::memcmp(w, p, wordLength))
			{
				ioIndex = bufLen + (p - pBelow);
				return true;
			}
		}
		index = bufLen - 1;
	}
	int len = bufLen - index;
	int wordSublen1 = min(wordLength, bufLen);
	auto pMin = mRangeEnd - wordSublen1;
	auto p = mRangeStart + index;
	for (; p >= mRangeStart; --p)
	{
		if (firstCharacter != *p)
		{
			continue;
		}
		if (p < pMin)
		{
			if (0 == ::memcmp(p, w, wordLength))
			{
				ioIndex = p - mRangeStart;
				return true;
			}
		}
		else
		{
			int sublen1 = mRangeEnd - p;
			if (0 == ::memcmp(p, w, sublen1))
			{
				if (int sublen2 = wordLength - sublen1)
				{
					if (sublen2 <= (int)mBytesBelow.size() &&
						0 == ::memcmp(mBytesBelow.data(), w + sublen1, sublen2))
					{
						ioIndex = p - mRangeStart;
						return true;
					}
				}
				else
				{
					ioIndex = p - mRangeStart;
					return true;
				}
			}
		}
	}

	return false;
}

bool FindHelper::FindUpAnyOfTwoFirstSequences(int& ioBeginIndex, int& outEndIndex)
{
	int index = ioBeginIndex;
	assert(mRangeStart + index <= mRangeEnd);

	auto word1 = mWhatCharactersVector[0];
	auto word2 = mWhatCharactersVector[1];
	const BYTE* w1 = word1.data();
	const BYTE* w2 = word2.data();
	const int word1Length = word1.size();
	const int word2Length = word2.size();
	const BYTE firstCharacter1 = *w1;
	const BYTE firstCharacter2 = *w2;
	if (firstCharacter1 == firstCharacter2)	// utf16-be
	{
		for (const BYTE* p = mRangeStart + index; --p >= mRangeStart;)
		{
			if (*p != firstCharacter1)
			{
				continue;
			}

			if (p + word1Length <= mRangeEnd)
			{
				if (0 == ::memcmp(w1, p, word1Length))
				{
					ioBeginIndex = p - mRangeStart;
					outEndIndex = ioBeginIndex + word1Length;
					return true;
				}
			}
			else
			{
				int sublen1 = mRangeEnd - p;
				if (0 == ::memcmp(w1, p, sublen1))
				{
					size_t sublen2 = word1Length - sublen1;
					if (sublen2 <= mBytesBelow.size() &&
						0 == ::memcmp(w1 + sublen1, mBytesBelow.data(), sublen2))
					{
						ioBeginIndex = p - mRangeStart;
						outEndIndex = ioBeginIndex + word1Length;
						return true;
					}
				}
			}

			if (p + word2Length <= mRangeEnd)
			{
				if (0 == ::memcmp(w2, p, word1Length))
				{
					ioBeginIndex = p - mRangeStart;
					outEndIndex = ioBeginIndex + word2Length;
					return true;
				}
			}
			else
			{
				int sublen1 = mRangeEnd - p;
				if (0 == ::memcmp(w2, p, sublen1))
				{
					size_t sublen2 = word2Length - sublen1;
					if (sublen2 <= mBytesBelow.size() &&
						0 == ::memcmp(w2 + sublen1, mBytesBelow.data(), sublen2))
					{
						ioBeginIndex = p - mRangeStart;
						outEndIndex = ioBeginIndex + word1Length;
						return true;
					}
				}
			}
		}
	}
	else
	{
		for (const BYTE* p = mRangeStart + index; --p >= mRangeStart;)
		{
			if (*p == firstCharacter1)
			{
				if (p + word1Length <= mRangeEnd)
				{
					if (0 == ::memcmp(w1, p, word1Length))
					{
						ioBeginIndex = p - mRangeStart;
						outEndIndex = ioBeginIndex + word1Length;
						return true;
					}
				}
				else
				{
					int sublen1 = mRangeEnd - p;
					if (0 == ::memcmp(w1, p, sublen1))
					{
						int sublen2 = word1Length - sublen1;
						if (sublen2 <= int(mBytesBelow.size()) &&
							0 == ::memcmp(w1 + sublen1, mBytesBelow.data(), sublen2))
						{
							ioBeginIndex = p - mRangeStart;
							outEndIndex = ioBeginIndex + word1Length;
							return true;
						}
					}
				}
			}
			else if (*p == firstCharacter2)
			{
				if (p + word2Length <= mRangeEnd)
				{
					if (0 == ::memcmp(w2, p, word1Length))
					{
						ioBeginIndex = p - mRangeStart;
						outEndIndex = ioBeginIndex + word2Length;
						return true;
					}
				}
				else
				{
					int sublen1 = mRangeEnd - p;
					if (0 == ::memcmp(w2, p, sublen1))
					{
						int sublen2 = word1Length - sublen1;
						if (sublen2 <= int(mBytesBelow.size()) &&
							0 == ::memcmp(w2 + sublen1, mBytesBelow.data(), sublen2))
						{
							ioBeginIndex = p - mRangeStart;
							outEndIndex = ioBeginIndex + word2Length;
							return true;
						}
					}
				}
			}
		}
	}

	return false;
}

//////////////////////////////////////////////

void FindHelper::ReadHexDigits()
{
	auto& v = mWhats[SearchKind::kBytesFromHexDigits];
	auto& text = mWhats[SearchKind::kUtf8];
	v.clear();
	BYTE x;
	bool isWaitingFirstDigit = true;
	bool wasError = false;
	int numberOfTrailingSeparators = 0;
	for (char ch : text)
	{
		bool isHexDigit = false;
		BYTE value = 0;
		if ('0' <= ch && ch <= '9')
		{
			isHexDigit = true;
			value = ch - '0';
		}
		else if ('A' <= ch && ch <= 'F')
		{
			isHexDigit = true;
			value = 0xA + (ch - 'A');
		}
		else if ('a' <= ch && ch <= 'f')
		{
			isHexDigit = true;
			value = 0xA + (ch - 'a');
		}

		if (isHexDigit)
		{
			if (isWaitingFirstDigit)
			{
				x = value;
				isWaitingFirstDigit = false;
				numberOfTrailingSeparators = 0;
			}
			else
			{
				v.push_back((x << 4) + value);
				isWaitingFirstDigit = true;
			}
			continue;
		}
		if (!isWaitingFirstDigit)
		{
			wasError = true;
			break;
		}
		if (' ' == ch)
		{
			continue;
		}
		if (',' == ch || ';' == ch)
		{
			++numberOfTrailingSeparators;
			if (1 == numberOfTrailingSeparators)
			{
				continue;
			}
		}
		wasError = true;
		break;
	}
	if (wasError || !isWaitingFirstDigit ||
		0 < numberOfTrailingSeparators)
	{
		v.clear();
	}
	// the vector v (=kByteFromHexDigits) contains bytes that will be searched
}

bool FindHelper::SearchStringDown(const ByteVector& inVector, int& outIndexBegin, int& outIndexEnd)
{
	bool result = false;
	if (inVector.empty())
	{
		return false;
	}
	const BYTE* pWordBegin = &inVector[0];
	const BYTE* pWordEnd = pWordBegin + inVector.size();
	const BYTE* pAboveBegin = mBytesAbove.empty() ? nullptr : mBytesAbove.data();
	const BYTE* pAboveEnd = pAboveBegin + mBytesAbove.size();

	for (auto p = pAboveBegin; p < pAboveEnd; ++p)
	{
		if (*p == *pWordBegin)
		{
			auto w = pWordBegin + 1;
			auto q = p + 1;
			while (w < pWordEnd && q < pAboveEnd)
			{
				if (*w != *q)
				{
					break;
				}
				++w; ++q;
			}
			if (q >= pAboveEnd)
			{
				q = mRangeStart;
				while (w < pWordEnd && q < mRangeEnd)
				{
					if (*w != *q)
					{
						break;
					}
					++w; ++q;
				}
			}
			if (w >= pWordEnd)
			{
				// found!
				outIndexBegin = -int(pAboveEnd - p);
				result = true;
				break;
			}
		}
	}
	if (!result)
	{
		for (auto p = mRangeStart; p < mRangeEnd; ++p)
		{
			if (*p == *pWordBegin)
			{
				auto w = pWordBegin + 1;
				auto q = p + 1;
				while (w < pWordEnd && q < mRangeEnd)
				{
					if (*w != *q)
					{
						break;
					}
					++w; ++q;
				}
				if (w >= pWordEnd)
				{
					outIndexBegin = int(p - mRangeStart);
					result = true;
					break;
				}
			}
		}
	}
	
	if (int lengthForSaving = min(mLengthForSavedBytes, (mRangeEnd - mRangeStart)))
	{
		mBytesAbove.resize(lengthForSaving);
		::memcpy(&mBytesAbove[0], mRangeEnd - lengthForSaving, lengthForSaving);
		mBytesBelow.clear();
	}
	
	if (result)
	{
		outIndexEnd = outIndexBegin + inVector.size();
	}
	return result;
}
bool FindHelper::SearchStringUp(const ByteVector& inVector, int& outIndexBegin, int& outIndexEnd)
{
	bool result = false;
	if (inVector.empty())
	{
		return false;
	}
	const BYTE* pWordBegin = &inVector[0];
	const BYTE* pWordEnd = pWordBegin + inVector.size();
	const BYTE* pBelowBegin = mBytesBelow.empty() ? nullptr : mBytesAbove.data();
	const BYTE* pBelowEnd = pBelowBegin + mBytesBelow.size();

	for (auto p = pBelowEnd; p > pBelowBegin; --p)
	{
		if (p[-1] != pWordEnd[-1])
		{
			continue;
		}
		auto w = pWordEnd - 1;
		auto q = p - 1;
		while (w > pWordBegin && q > pBelowBegin)
		{
			if (w[-1] != q[-1])
			{
				break;
			}
			--w; --q;
		}
		if (q == pBelowBegin)
		{
			q = mRangeEnd;
			while (w > pWordBegin && q > mRangeStart)
			{
				if (w[-1] != q[-1])
				{
					break;
				}
				--w; --q;
			}
		}
		if (w == pWordBegin)
		{
			outIndexBegin = mRangeEnd - mRangeStart +
				(p - pBelowBegin) - (pWordEnd - pWordBegin);
			result = true;
			break;
		}
	}
	if (!result)
	{
		auto pRangeMin = mRangeStart + inVector.size();
		for (auto p = mRangeEnd; p >= pRangeMin; --p)
		{
			if (p[-1] != pWordEnd[-1])
			{
				continue;
			}
			auto w = pWordEnd - 1;
			auto q = p - 1;
			while (w > pWordBegin)
			{
				if (w[-1] != q[-1])
				{
					break;
				}
				--w; --q;
			}
			if (w == pWordBegin)
			{
				outIndexBegin = q - mRangeStart;
				result = true;
				break;
			}
		}
	}
	mBytesAbove.clear();
	auto lengthToCopy = min(mLengthForSavedBytes, mRangeEnd - mRangeStart);
	mBytesBelow.resize(lengthToCopy);
	if (lengthToCopy)
	{
		::memcpy(mBytesBelow.data(), mRangeStart, lengthToCopy);
	}

	if (result)
	{
		outIndexEnd = outIndexBegin + inVector.size();
	}
	return result;
}
bool FindHelper::SearchAllDown(int& outIndexBegin, int& outIndexEnd, int& outSearchKind)
{
	int wordIndexes[SearchKind::kTotalCount] = { 0 };
	std::vector<int> validKinds;
	validKinds.reserve(SearchKind::kTotalCount);
	for (int k = SearchKind::kTotalCount; k--;)
	{
		if (!mWhats[k].empty())
		{
			validKinds.push_back(k);
		}
	}
	const BYTE* pAboveBegin = mBytesAbove.empty() ? nullptr : mBytesAbove.data();
	const BYTE* pAboveEnd = pAboveBegin + mBytesAbove.size();

	bool result = false;
	for (auto p = pAboveBegin; p < pAboveEnd; ++p)
	{
		BYTE ch = *p;
		for (int sk : validKinds)
		{
			if (ch == mWhats[sk].front())
			{
				// .....
			}
		}
	}
	if (!result)
	{
		for (auto p = mRangeStart; p < mRangeEnd && !result; ++p)
		{
			BYTE ch = *p;
			for (int k : validKinds)
			{
				if (ch != mWhats[k].front())
				{
					continue;
				}
				auto w = &mWhats[k][1];
				auto wEnd = w - 1 + mWhats[k].size();
				auto q = p + 1;
				while (w < wEnd && q < mRangeEnd)
				{
					if (*w != *q)
					{
						break;
					}
					++w; ++q;
				}
				if (w == wEnd)
				{
					outIndexBegin = p - mRangeStart;
					outIndexEnd = outIndexBegin + mWhats[k].size();
					outSearchKind = k;
					result = true;
					break;
				}
			}
		}
	}
	if (int lengthForSaving = min(mLengthForSavedBytes, (mRangeEnd - mRangeStart)))
	{
		mBytesAbove.resize(lengthForSaving);
		::memcpy(&mBytesAbove[0], mRangeEnd - lengthForSaving, lengthForSaving);
		mBytesBelow.clear();
	}
	return result;
}
bool FindHelper::SearchAllUp(int& outIndexBegin, int& outIndexEnd, int& outSearchKind)
{
	return false;
}
